#include "TriangularObstacle.h"
#include "TriangularSketcher.h"

TriangularObstacle::TriangularObstacle(void){
	this->setType("Obstacle");
}

TriangularObstacle::TriangularObstacle( Position * p1, Position * p2, Position * p3 ){
	this->setType("Obstacle");
	this->setP1(p1);
	this->setP2(p2);
	this->setP3(p3);
	Position * leftPoint;
	Position * rightPoint;
	float opuesto;
	float adyacente;
	int yEdge = -1;
	// Arista 1-2.
	leftPoint = p1->getPixelX() > p2->getPixelX()? p2 : p1;
	rightPoint = p1->getPixelX() > p2->getPixelX()? p1 : p2;
	opuesto = rightPoint->getPixelY()-leftPoint->getPixelY();
	adyacente = rightPoint->getPixelX()-leftPoint->getPixelX();
	this->m1 = opuesto/adyacente;
	this->ord1 = leftPoint->getPixelY();
	// Arista 1-3.
	leftPoint = p1->getPixelX() > p3->getPixelX()? p3 : p1;
	rightPoint = p1->getPixelX() > p3->getPixelX()? p1 : p3;
	opuesto = rightPoint->getPixelY()-leftPoint->getPixelY();
	adyacente = rightPoint->getPixelX()-leftPoint->getPixelX();
	this->m2 = opuesto/adyacente;
	this->ord2 = leftPoint->getPixelY();
	// Arista 2-3.
	leftPoint = p2->getPixelX() > p3->getPixelX()? p3 : p2;
	rightPoint = p2->getPixelX() > p3->getPixelX()? p2 : p3;
	opuesto = rightPoint->getPixelY()-leftPoint->getPixelY();
	adyacente = rightPoint->getPixelX()-leftPoint->getPixelX();
	this->m3 = opuesto/adyacente;
	this->ord3 = leftPoint->getPixelY();

}
/*
void TriangularObstacle::fillEdge( Position * p1, Position * p2, list<Position*> * edge ){
	int x = 0;
	int y = 0;

	Position * leftPoint = p1->getPixelX() > p2->getPixelX()? p2 : p1;
	Position * rightPoint = p1->getPixelX() > p2->getPixelX()? p1 : p2;
	Position * topPoint = p1->getPixelY() > p2->getPixelY()? p1 : p2;
	Position * bottonPoint = p1->getPixelY() > p2->getPixelY()? p2 : p1;

	float opuesto = rightPoint->getPixelY()-leftPoint->getPixelY();
	float adyacente = rightPoint->getPixelX()-leftPoint->getPixelX();
	float m = opuesto/adyacente;
	float ord = leftPoint->getPixelY();
	Position * edegePixel;
	if(leftPoint->getPixelX() != rightPoint->getPixelX()) {
		for(x = leftPoint->getPixelX(); x <= rightPoint->getPixelX(); x++ ) {
			edegePixel = new Position();
			y = fx(x-leftPoint->getPixelX(),m,ord);
			edegePixel->setPixel(x,y);
			edge->push_front(edegePixel);
		}
	}else {
		for(y = bottonPoint->getPixelY(); y < topPoint->getPixelY(); y++ ) {
			edegePixel = new Position();
			edegePixel->setPixel(bottonPoint->getPixelX(),y);
			edge->push_front(edegePixel);
		}
	}
}*/

void TriangularObstacle::setP1( Position * p1 ){
	this->p1 = p1;
}

void TriangularObstacle::setP2( Position * p2 ){
	this->p2 = p2;
}

void TriangularObstacle::setP3( Position * p3 ){
	this->p3 = p3;
}

Position * TriangularObstacle::getP1( void ){
	return this->p1;
}

Position * TriangularObstacle::getP2( void ){
	return this->p2;
}

Position * TriangularObstacle::getP3( void ){
	return this->p3;
}

int TriangularObstacle::fx(int x, float m, float o) {
	return x*m + o;
}

int TriangularObstacle::include( Position * point ){
	int x = point->getPixelX();
	int y = point->getPixelY();

	int y1_2 = this->getPointEdge1_2(point);
	int y1_3 = this->getPointEdge1_3(point);
	int y2_3 = this->getPointEdge2_3(point);
	bool onBorder = (y == y1_2 || y == y1_3 || y == y2_3);
	bool included = (
		((min(y1_2,y1_3) > 0) && ( y < max(y1_2,y1_3) && y > min(y1_2,y1_3)))
      ||((min(y1_2,y2_3) > 0) && ( y < max(y1_2,y2_3) && y > min(y1_2,y2_3)))
	  ||((min(y1_3,y2_3) > 0) && ( y < max(y1_3,y2_3) && y > min(y1_3,y2_3))));
	if(onBorder) {
		return 0;
	}
	if(included) {
		return 1;
	}
	return -1;
}

int TriangularObstacle::getPointEdge1_2( Position * p ){	
	int x = p->getPixelX();
	int y = p->getPixelY();
	Position * leftPoint;
	Position * rightPoint;
	float opuesto;
	float adyacente;
	int yEdge = -1;

	// Arista 1-2.
	leftPoint = p1->getPixelX() > p2->getPixelX()? p2 : p1;
	rightPoint = p1->getPixelX() > p2->getPixelX()? p1 : p2;
	if(leftPoint->getPixelX() != rightPoint->getPixelX()) {
		if( x <= rightPoint->getPixelX() && x >= leftPoint->getPixelX() ) {
			yEdge = this->fx(x-leftPoint->getPixelX(),m1,ord1); // Ecuacion de la recta edge 1.
		}
	}else {
		if(x == leftPoint->getPixelX() && y > min(leftPoint->getPixelY(),rightPoint->getPixelY()) && y < max(leftPoint->getPixelY(),rightPoint->getPixelY())) {
			yEdge = y; // Si la recta es vertical, en caso q la x coincida con el punto, el tambien lo hace.
		}
	}
	return yEdge;
}

int TriangularObstacle::getPointEdge1_3( Position * p ){
	int x = p->getPixelX();
	int y = p->getPixelY();
	Position * leftPoint;
	Position * rightPoint;
	float opuesto;
	float adyacente;
	int yEdge = -1;

	// Arista 1-3.
	leftPoint = p1->getPixelX() > p3->getPixelX()? p3 : p1;
	rightPoint = p1->getPixelX() > p3->getPixelX()? p1 : p3;
	if(leftPoint->getPixelX() != rightPoint->getPixelX()) {
		if( x <= rightPoint->getPixelX() && x >= leftPoint->getPixelX() ) {
			yEdge = this->fx(x-leftPoint->getPixelX(),m2,ord2); // Ecuacion de la recta edge 2.
		}
	}else {
		if(x == leftPoint->getPixelX() && y > min(leftPoint->getPixelY(),rightPoint->getPixelY()) && y < max(leftPoint->getPixelY(),rightPoint->getPixelY())) {
			yEdge = y; // Si la recta es vertical, en caso q la x coincida con el punto, el tambien lo hace.
		}
	}
	return yEdge;
}

int TriangularObstacle::getPointEdge2_3( Position * p ){
	int x = p->getPixelX();
	int y = p->getPixelY();
	Position * leftPoint;
	Position * rightPoint;
	float opuesto;
	float adyacente;
	int yEdge = -1;

	// Arista 2-3.
	leftPoint = p2->getPixelX() > p3->getPixelX()? p3 : p2;
	rightPoint = p2->getPixelX() > p3->getPixelX()? p2 : p3;
	if(leftPoint->getPixelX() != rightPoint->getPixelX()) {
		if( x <= rightPoint->getPixelX() && x >= leftPoint->getPixelX() ) {
			yEdge = this->fx(x-leftPoint->getPixelX(),m3,ord3); // Ecuacion de la recta edge 3.
		}
	}else {
		if(x == leftPoint->getPixelX() && y > min(leftPoint->getPixelY(),rightPoint->getPixelY()) && y < max(leftPoint->getPixelY(),rightPoint->getPixelY())) {
			yEdge = y; // Si la recta es vertical, en caso q la x coincida con el punto, el tambien lo hace.
		}
	}
	return yEdge;
}


//**************************************************************************************************


float TriangularObstacle::getMinXPos(){
	float minimo = min(this->getP1()->getAxisX(),this->getP2()->getAxisX());
	minimo =  min(minimo,this->getP3()->getAxisX());
	return minimo;
}

float TriangularObstacle::getMinYPos(){	
	float minimo = min(this->getP1()->getAxisY(),this->getP2()->getAxisY());
	minimo =  min(minimo,this->getP3()->getAxisY());
	return minimo;
}

float TriangularObstacle::getMaxXPos(){	
	float maximo = max(this->getP1()->getAxisX(),this->getP2()->getAxisX());
	maximo =  max(maximo,this->getP3()->getAxisX());
	return maximo;
}

float TriangularObstacle::getMaxYPos(){
	float maximo = max(this->getP1()->getAxisY(),this->getP2()->getAxisY());
	maximo =  max(maximo,this->getP3()->getAxisY());
	return maximo;
}

void TriangularObstacle::setPosition(Position * position){
	this->position = position;
}

Position *TriangularObstacle::getPosition(){
	return this->position;
}

Color * TriangularObstacle::getElementColor(){
	return this->elementColor;
}

void TriangularObstacle::setElementColor(Color * color){
	this->elementColor = color;
}

Texture *TriangularObstacle::getTexture(){
	return this->texture;
}

void TriangularObstacle::setTexture(Texture *texture){
	this->texture = texture;
}

Color * TriangularObstacle::getLineColor()
{
	return this->lineColor;
}

void TriangularObstacle::setLineColor( Color * color )
{
	this->lineColor = color;
}

void TriangularObstacle::draw()
{
	Sketcher* sketcher = new TriangularSketcher(this);
	sketcher->draw();
	delete(sketcher);
}
